const db = require("../config/mysql");
const LOG_TYPES = require("../constants/logTypes");
const { getUserIdFromToken, getClientType, getExtractIp } = require("./utils");

// 内存队列
const logQueue = [];

/** 将日志推入队列（异步写） **/
function pushToQueue(logData) {
  logQueue.push(logData);
}

/** 后台消费者（每500ms写一次） **/
setInterval(async () => {
  if (logQueue.length === 0) return;

  const logs = logQueue.splice(0, logQueue.length); // 一次取完

  const sql = `
    INSERT INTO sys_logs (op_type, op_desc, ip, user_id, client_type, create_time)
    VALUES ?
  `;

  const values = logs.map((item) => [
    item.op_type,
    item.op_desc,
    item.ip,
    item.user_id,
    item.client_type,
    new Date(),
  ]);

  try {
    await db.query(sql, [values]);
    console.log(`[LOG BATCH INSERT] ${values.length} rows`);
  } catch (err) {
    console.error("[LOG BATCH ERROR]", err);
  }
}, 500);

/**
 * 写日志（轻量、自动UserId、自动IP）
 * 生成日描述模板
 */
const logService = {
  /*
   * @desc 写日志
   * @params req 请求对象 -必填
   * @param data 日志数据 -必填
   * @parmas data.user_id 用户ID可选，登录的时候要手动传递，此时用户还没有登录，没有token，也没有user_id。其他接口不用传
   * @param data.op_type 操作类型-必填
   * @param data.op_desc 日志描述-必填
   *
   * @return void
   * */
  addLog(req, { user_id = null, op_type, op_desc = "" }) {
    // 获取操作类型
    // actionType 经过映射处理，例如 CREATE_PO → 4
    let opType;
    console.log("[LOG] 日志操作类型:", op_type);

    // 处理 action：数字直接使用，字符串查枚举映射
    if (typeof op_type === "number") {
      opType = op_type; // 数字直接使用
    } else if (typeof action === "string") {
      opType = LOG_TYPES[action]; // 字符串映射
    }

    if (!opType) {
      console.warn("未知日志操作类型:", op_type);
      return;
    }
    // 自动解析 ip
    const ip = getExtractIp(req);
    // 自动解析 user_id（业务端不需要传）
    const uid = user_id ? user_id : getUserIdFromToken(req);
    console.log("[LOG] uid is:", uid);
    // 自动解析 client_type
    const clientType = getClientType(req);

    pushToQueue({
      op_type: opType,
      op_desc,
      ip,
      user_id: uid,
      client_type: clientType,
    });
  },

  /*
    * @desc 格式化日志描述
    * @param actionType 操作类型
    * @param data 日志数据
    * data 格式参考：根据不同的actionType，data 的格式不同，下面的参数都是可选的
    *  {
    *   user_name: '张三',
    *   user_id: 1001,
    *   name: '1号仓库',
    *   spec: '500g/包',
    *   role: '管理员'
    *   client_type: 'WEB'
    *   po_no:""  采购订单号
    *   total_qty: 5,  总数量
    *   total_amount: 310.00,  总金额
    *   reason: '日常烹饪'  入库原因
    *   message 调试信息
    *  }
    * @return string
    * 示例参考（每种类型对应的示例）：
    * LOGIN:用户 张三（ID: 1001）登录系统，客户端：WEB
    * LOGOUT:用户 张三（ID: 1001）退出系统
    * ADD_USER:添加用户 王五（ID: 2002），角色：管理员
    * RESET_PWD:重置用户 赵六（ID: 2003）的密码
    * DISABLE_USER:禁用用户 李四（ID: 2004），原因：违规操作
    * ENABLE_USER:启用用户 李四（ID: 2004）

    * ADD_INGREDIENT: 添加新食材：鸡胸肉（规格：500g/包）
    * DISABLE_INGREDIENT: 停用食材：三文鱼，原因：供应商停供
    * ENABLE_INGREDIENT: 启用食材：三文鱼

    * ADD_WAREHOUSE: 添加新仓库：冷藏库（位置：一楼西侧）
    * DISABLE_WAREHOUSE: 停用仓库：冷冻库，原因：设备检修
    * ENABLE_WAREHOUSE: 启用仓库：冷冻库

    * CREATE_PO: 创建采购订单 PO20251012011，总数：5 件，总金额：￥310.00
    * CONFIRM_PO: 确认采购订单 PO20251012011，总数：5 件，总金额：￥310.00
    * PO_PARTIAL_STOCK_IN: 采购订单 PO20251012011 部分入库，本次入库 2 件，总数 5 件
    * PO_COMPLETE: 采购订单 PO20251012011 已完成，总数：5 件，总金额：￥310.00

    * STOCK_IN: 完成入库单 IN20251003001（采购入库），总数：20 件，总金额：￥520.00
    * STOCK_OUT: 完成出库单 OUT20251004001（日常烹饪），总数：10 件，总金额：￥200.00
    * STOCK_ADJUSTMENT: 调整物品 牛肉 在 主仓库 的库存，原因：盘亏
    * STOCK_TAKING: 完成盘点单 PD20251012011，盘点仓库：主仓库，共 120 个物品

    * DEBUG: 调试：库存计算结果为 28
    */
  formatLog(actionType, data) {
    const t = {
      // 用户与权限管理
      LOGIN: `用户 ${data.user_name}（ID: ${data.user_id}）登录系统，客户端：${data.client_type}`,
      LOGOUT: `用户 ${data.user_name}（ID: ${data.user_id}）退出系统`,
      ADD_USER: `添加用户 ${data.new_user_name}（ID: ${data.new_user_id}），角色：${data.role}`,
      RESET_PWD: `重置用户 ${data.user_name}（ID: ${data.user_id}）的密码`,
      DISABLE_USER: `禁用用户 ${data.user_name}（ID: ${data.user_id}），原因：${data.reason}`,
      ENABLE_USER: `启用用户 ${data.user_name}（ID: ${data.user_id}）`,

      // 食材操作
      ADD_INGREDIENT: `添加新食材：${data.name}（编号: ${data.code}，ID: ${data.goods_id}，规格：${data.spec}）`,
      DISABLE_INGREDIENT: `停用食材：${data.name}（编号: ${data.code}，ID: ${data.goods_id}，规格：${data.spec}）`,
      ENABLE_INGREDIENT: `启用食材：${data.name}（编号: ${data.code}，ID: ${data.goods_id}，规格：${data.spec}）`,

      // 仓库操作
      ADD_WAREHOUSE: `添加新仓库：${data.name}（编号: ${data.code}，ID: ${data.house_id}，位置：${data.location}）`,
      DISABLE_WAREHOUSE: `停用仓库：${data.name}（编号: ${data.code}，ID: ${data.house_id}，位置：${data.location}）`,
      ENABLE_WAREHOUSE: `启用仓库：${data.name}（编号: ${data.code}，ID: ${data.house_id}，位置：${data.location}）`,

      // 采购管理
      CREATE_PLAN: `创建计划 ${data.plan_no}，共 ${data.total_items} 项，负责人：${data.owner_name}`,
      CREATE_PO: `创建采购订单 ${data.po_no}，总数：${data.total_qty} 件，总金额：￥${data.total_amount}`,
      CONFIRM_PO: `确认采购订单 ${data.po_no}，总数：${data.total_qty} 件，总金额：￥${data.total_amount}`,
      PO_PARTIAL_STOCK_IN: `采购订单 ${data.po_no} 部分入库，本次入库 ${data.stock_in_qty} 件，总数 ${data.total_qty} 件`,
      PO_COMPLETE: `采购订单 ${data.po_no} 已完成，总数：${data.total_qty} 件，总金额：￥${data.total_amount}`,

      // 库存管理
      STOCK_IN: `完成入库单 ${data.no}，总数：${data.total_qty} 件，总金额：￥${data.total_amount}`,
      STOCK_OUT: `完成出库单 ${data.no}，总数：${data.total_qty} 件，总金额：￥${data.total_amount}`,
      STOCK_ADJUSTMENT: `调整物品 ${data.item_name} 在 ${data.warehouse_name} 的库存，原因：${data.reason}`,
      STOCK_TAKING: `${data.name} 完成盘点,盘点仓库：${data.warehouse_name}，共 ${data.item_count} 个物品,变化数量 ${data.change_count}`,

      // 调试
      DEBUG: `调试：${data.message}`,
    };
    // 根据值，找到对应的键(key)
    const targetValue = actionType;
    let foundKey = null;
    // Object.keys() 返回一个包含所有键的数组
    foundKey = Object.keys(LOG_TYPES).find(
      (key) => LOG_TYPES[key] === targetValue
    );

    return t[foundKey] || "未知日志类型";
  },
};

module.exports = logService;
